package vip.manda.framework.web;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import vip.manda.framework.bean.BeanContainer;
import vip.manda.framework.bean.BeanFactory;
import vip.manda.framework.config.WebConfig;
import vip.manda.framework.bean.Singleton;
import vip.manda.framework.core.Configs;
import vip.manda.framework.core.Function;
import vip.manda.framework.util.Triad;
import vip.manda.framework.log.Log;
import vip.manda.framework.log.LogFactory;
import vip.manda.framework.web.http.Filter;
import vip.manda.framework.web.server.TomcatServer;
import vip.manda.framework.web.server.WebServer;

import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author hongda.li 2022-04-11 15:17
 */
@Function(order = Function.Common.WEB_FUNCTION)
public class WebFunction implements Function.FunctionMethod {
    private static final Log log = LogFactory.getLog();
    private static WebServer SERVER;
    private static final List<Triad<Class<?>, Object, Method>> FILTERS = new ArrayList<>();
    private static final List<Triad<String, Class<?>, Method>> CONTROLLERS = new ArrayList<>();

    /**
     * 获取已排序的过滤器集合
     * @return 过滤器集合
     */
    public static List<Triad<Class<?>, Object, Method>> getFilters() {
        return FILTERS;
    }

    /**
     * 获取所有Api信息
     * @return Api集合
     */
    public static List<String> getApis(){
        return CONTROLLERS.stream().map(Triad::getX).collect(Collectors.toList());
    }

    /**
     * 获取内嵌式Web服务器
     * 统一启动和停止方法
     * @return Web服务器子类
     */
    public static WebServer getServer(){
        return SERVER;
    }

    /**
     * 获取控制器
     * @param uri uri
     * @return 对应的控制器
     */
    public static Triad<String, Class<?>, Method> getController(String uri){
        return CONTROLLERS.stream().filter(controller -> controller.getX().equals(uri)).findFirst().orElse(null);
    }

    /**
     * 获取Api对应的方法集合
     * @param uri uri
     * @return 方法集合
     */
    public static vip.manda.framework.web.Method[] getApiMethodType(String uri){
        Triad<String, Class<?>, Method> controller = getController(uri);
        return controller != null ? AnnotationUtil.getAnnotationValue(controller.getZ(), Api.class, "method") : null;
    }

    public WebFunction() {
        log.func("execute function[{}]", WebFunction.class.getName());
    }

    @Override
    public void doFunction(Set<Class<?>> classes) {
        // 提供Web默认配置
        Configs.setDefaultConfig(WebConfig.PORT, WebConfig.Value.PORT);
        Configs.setDefaultConfig(WebConfig.ROOT, WebConfig.Value.ROOT);
        Configs.setDefaultConfig(WebConfig.CONTEXT, WebConfig.Value.CONTEXT);

        // 处理Web相关服务
        handleFilter(classes);
        handleController(classes);
        handleServer(classes);
    }

    /**
     * 处理过滤器
     * 获取所有实现了Filter接口的过滤器，并按照优先级排序
     * 存储在有序的List集合中
     * @param classes 框架扫描到类集合
     */
    private void handleFilter(Set<Class<?>> classes){
        classes.stream()
                .filter(Filter.class::isAssignableFrom)
                .sorted(Comparator.comparingInt(clazz
                        -> ReflectUtil.invoke(ReflectUtil.newInstance(clazz)
                        , ReflectUtil.getMethodByName(clazz, Filter.Common.GET_ORDER))))
                .collect(Collectors.toList())
                .forEach(clazz -> FILTERS.add(Triad.of(clazz
                        , ReflectUtil.newInstance(clazz)
                        , ReflectUtil.getMethodByName(clazz, Filter.Common.DO_FILTER))));
        FILTERS.forEach(filter -> log.info("Capture a filter[{}]", filter.getX().getName()));
    }

    /**
     * 处理控制器
     * 扫描控制器上的@Api注解，获取映射路径与映射方法信息
     * @param classes 框架扫描到类集合
     */
    private void handleController(Set<Class<?>> classes){
        BeanContainer container = BeanFactory.getContainer();
        classes.stream()
                .filter(clazz -> AnnotationUtil.hasAnnotation(clazz, Singleton.class))
                .filter(container::exists)
                .collect(Collectors.toList()).forEach(controller -> {
                    Api controllerApi = controller.getAnnotation(Api.class);
                    String apiOnController = controllerApi != null
                            ? "".equals(controllerApi.value()) ? "/" + controller.getSimpleName() : StrUtil.addPrefixIfNot(controllerApi.value(),"/")
                            : "";
                    Arrays.asList(ReflectUtil.getMethods(controller, method -> AnnotationUtil.hasAnnotation(method, Api.class)))
                            .forEach(method -> {
                                Api methodApi = method.getAnnotation(Api.class);
                                String apiOnMethod = "".equals(methodApi.value())
                                        ? "/" + method.getName()
                                        : StrUtil.addPrefixIfNot(methodApi.value(),"/");
                                if (controllerApi == null){
                                    CONTROLLERS.add(Triad.of(apiOnMethod, controller, method));
                                    log.info("Capture a controller[{}][{}][{}]", apiOnMethod, controller.getName(), method.getName());
                                }else {
                                    CONTROLLERS.add(Triad.of(apiOnController + apiOnMethod, controller, method));
                                    log.info("Capture a controller[{}][{}][{}]", apiOnController + apiOnMethod, controller.getName(), method.getName());
                                }
                            });
                });
    }

    /**
     * 处理内嵌式服务器
     * 获取WebServer的子类，若无实现类，则默认采用TomcatServer
     * @param classes 框架扫描到类集合
     */
    private void handleServer(Set<Class<?>> classes){
        Class<?> serverClass = classes.stream()
                .filter(WebServer.class::isAssignableFrom)
                .filter(clazz -> clazz != WebServer.class)
                .findFirst().orElse(TomcatServer.class);
        SERVER = (WebServer) ReflectUtil.newInstance(serverClass);
        SERVER.startServer();
    }
}
